# encoding: UTF-8


import threading
import zmq
import copy
from py_at.rpc.RecObject import RpcObject
import queue

#------------------------------------------------------------
class RemoteException(Exception):
    def __init__(self,value):
        self.__value = value
    def __str__(self):
        return self.__value

#--------------------------------------------------------------
class RpcClient(RpcObject):
    """RPC客户端"""
    def __init__(self,reqAddress,subAddress):
        super(RpcClient,self).__init__()
        '''zmq端口相关'''
        self.__reqAddress = reqAddress
        self.__subAddress = subAddress

        self.__context = zmq.Context()
        self.__socketREQ = self.__context.socket(zmq.REQ)        #客户端请求  服务请应该有个REP 就是相应的意思
        self.__socketSUB = self.__context.socket(zmq.SUB)        #广播所有client，没有队列缓存，断开连接数据将永远丢失。client可以进行数据过滤。 对应的服务端是PUB

        #工作线程相关，用于处理服务器推送的数据
        self.__active = False
        self.__thread = threading.Thread(target=self.run)
    #-------------------------------------------------------
    def __getattr__(self, name):
        """实现远程调用功能，主要执行远程调用任务，从客户段直接调用服务器端的调用"""
        def dorpc(*args,**kwargs):
            #生成请求
            req = [name,args,kwargs]
            #序列化打包请求
            reqb = self.pack(req)

            #发送请求并等待回应
            self.__socketREQ.send(reqb)
            reqb = self.__socketREQ.recv()

            #序列号解包回应
            req = self.unpack(reqb)
            #如果正常返回则返回结果，调用失败则触发异常
            if req[0]:
                return req[1]
            else:
                raise RemoteException(req[1])
        return dorpc
    #------------------------------------------------------------
    def start(self):
        """启动客户端 链接端口"""
        self.__socketREQ.connect(self.__reqAddress)
        self.__socketSUB.connect(self.__subAddress)
        #将服务器设为启动
        self.__active = True
        #启动工作线程

        # if not self.__thread.isAlive():
        #     print("线程启动了")
        #     self.__thread.start()
    #-----------------------------------------------------------
    def stop(self):
        """关闭工作线程"""
        #等待线程工作完毕之后退出
        if self.__thread.isAlive():
            self.__thread.join()
        self.__active = False
    #----------------------------------------------------------------------
    def run(self):
        """客户端运行函数"""
        while self.__active:
            # 使用poll来等待事件到达，等待1秒（1000毫秒）
            if not self.__socketSUB.poll(1000):
                continue

            # 从订阅socket收取广播数据
            topic, datab = self.__socketSUB.recv_multipart()

            # 序列化解包
            data = self.unpack(datab)

            # 调用回调函数处理
            self.callback(topic, data)

    def callback(self,topic,data):
        """回调函数，必须由用户实现"""
        raise NotImplementedError

    def subscribeTopic(self,topic):
        """
        订阅特定主题的广播数据
        可以使用topic = ''来订阅所有主题
        注意topic 必须是ascii编码
        """
        topic=self.pack(topic)
        self.__socketSUB.setsockopt(zmq.SUBSCRIBE,topic)

class RsClient(RpcClient):
    """RPC服务客户端"""
    def __init__(self,reqAddress,subAddress):
        """Constructor"""
        super(RsClient,self).__init__(reqAddress,subAddress)
        self.eventEngine = None
    #--------------------------------------------------------
    def callback(self,topic,data): #这个函数是从上层函数继承的(上层函数有对这个函数的调用  用来接受PUB服务器函数返回的信息   )
        """把从服务器得到的事件 推送到中转eventEngine里面"""
        self.eventEngine.put(data)   #直接放入事件引擎中
    #----------------------------------------------------------
    def init(self,eventEngine):
        """初始化"""
        self.eventEngine = eventEngine #绑定事件引擎对象
        self.usePickle()               #这个函数是爷爷类的使用cpickle序列
        self.subscribeTopic('')
        self.start()                   #启动工作父类的工作线程



class ObjectProxy(object):
    def __init__(self,name,client):
        self.nameList = name
        self.client = client

    def __getattr__(self, name):
        print("进过了")
        '''暂时觉得没什么用处 这种调用最恶心了'''
        newNameList = copy.copy(self.nameList)
        newNameList.append(name)
        # 创建代理对象
        proxy = ObjectProxy(newNameList,self.client)

        #缓存代理对象
        self.__dict__[name] = proxy

        #返回
        return proxy
    def __call__(self,*args,**kwargs):
        d = {}
        d['nameList'] = self.nameList
        d['args'] = args
        d['kwargs'] = kwargs
        return self.client.call(d)

class MainEngineProxy(object):
    """constructor"""
    #-------------------------------------------------------
    def __init__(self,enentEngine):
        self.eventEngine = enentEngine
        self.client =None

    #--------------------------------------------------------
    def init(self,reqAddress,subAddress):

        """init"""
        self.client = RsClient(reqAddress,subAddress)
        self.client.init(self.eventEngine)
    #--------------------------------------------------------
    def __getattr__(self, name):
        #生成属性名称层级列表
        nameList = [name]
        proxy = ObjectProxy(nameList,self.client) #封装成对象  这个对象里面有个__call__函数  这个调用的是client.call  直接就到RsClient.__getattr__里面了 返回函数
        #缓存属性代理对象，使得后续调用无需新建  下次调用的时候直接从__dict__里面调用走了 所以就不用经过这个函数了
        self.__dict__[name] = proxy

        return proxy
    #---------------------------------------------------------
    def getApp(self,name):
        return self.__getattr__(name)

class enentE(object):
    def __init__(self):
        pass
    def put(self,s):        #轮询每秒调用次
        print ("放里面了一个数据%s" %s)


#-------------------------------------------------------------------------------------------------------------------------------------------------------
def jiandanceshi():
    """简单测试  """
    reqAddress = 'tcp://localhost:2014'
    subAddress = 'tcp://localhost:0602'
    ene = enentE()
    ME = MainEngineProxy(ene)
    ME.init(reqAddress, subAddress)
    #print(ME.dome1)
    print(ME.canshu)
    print(ME.dome1())  # 远程调用后台的方法
    print(ME.dome2("从前台传参数"))  # 远程调用后台的方法加参数
    print(ME.canshu())  # 远程调用后台的属性


def shijiceshi():
    reqAddress = 'tcp://localhost:2014'
    subAddress = 'tcp://localhost:0602'
    ene = enentE()
    ME = MainEngineProxy(ene)
    ME.init(reqAddress, subAddress)
    ME.load_strategy_json()  # 加载策略配置文件
    ME.load_strategyname()  # 加载所有策略类名
    ME.load_all_Instrument()  # 加载所有合约信
    stra_json_array=[]
    stra_json_array.clear()

    for k, v in ME.CanshuDict().items():
        tringstatus = "false"  # 判断是否已经绑定实盘交易  默认是没有绑定
        print(k)
        print(v)
if __name__ =="__main__":
    jiandanceshi()  #启动这个必须记得启动匹配的 server服务
    shijiceshi()




